﻿using System;
using System . Collections . Generic;
using System . Collections . ObjectModel;
using System . Linq;
using System . Text;
using System . Xml . Linq;
using GameClassLibrary . Players . Models;

namespace GameClassLibrary . Players

{
    public class Player : Maps . MapObject
    {
        [SaveReference]
        public PlayerModel Model { get; private set; }

        public bool CanGetCharge
        {
            get
            {
                if ( State == PlayerState . Normal )
                {
                    bool blockCharge=false;

                    foreach ( var item in Buffs )
                    {
                        blockCharge |= item . BlockGetCharge;
                    }
                    return !blockCharge;
                }
                else
                {
                    return false;
                }
            }
        }

        [SaveValue]
        public PlayerState State { get;  set; }


        public TimeSpan StateUpTime { get;  set; }

        public DateTime StateStartDate { get;  set; }

        public long Money { get; private set; }

        public PlayerDirection Direction { get; set; }

        public int NumberOfTouzi { get; set; } = 1;

        public long GamePoint { get; set; }

        [SaveValueList]
        public List<Cards . Card> Cards { get;  set; } = new List<Cards . Card> ( );

        public Dictionary<Stocks . Stock , long> Stocks { get;  set; } = new Dictionary<Stocks . Stock , long> ( );

        [SaveValueList]
        public List<Banks . SavingBankProof> SavedMoney { get;  set; }

        [SaveValueList]
        public List<Banks . BorrowingBankProof> BorrowedMoney { get; set; }

        [SaveReference]
        public Maps . Road Position { get; set; }

        [SaveReferenceList]
        public List<Buffs . PlayerBuff> Buffs { get; private set; } = new List<Buffs . PlayerBuff> ( );

        [SaveValue]
        public bool CanMoveToday { get;  set; }

        public void Move ( )
        {
            if ( CanMoveToday )
            {
                CanMoveToday = false;
                for ( int touzi = 0 ; touzi < NumberOfTouzi ; touzi++ )
                {
                    int blockOfMove= Game . Current . Randomer . Next ( 1 , 7 );
                    for ( int move = 0 ; move < blockOfMove ; move++ )
                    {

                        switch ( Direction )
                        {
                            case PlayerDirection . Forward:
                                {
                                    if ( Position . ForwardRoad . BlockMoving )
                                    {
                                        goto endMoving;
                                    }
                                    else
                                    {
                                        do
                                        {
                                            Position = Position . ForwardRoad;
                                        } while ( Position . Jumper );
                                    }
                                    Position = Position . ForwardRoad;
                                    break;
                                }
                            case PlayerDirection . Backward:
                                {
                                    if ( Position . BackwardRoad . BlockMoving )
                                    {
                                        goto endMoving;
                                    }
                                    else
                                    {
                                        do
                                        {
                                            Position = Position . BackwardRoad;
                                        } while ( Position . Jumper );
                                    }
                                    Position = Position . BackwardRoad;
                                    break;
                                }
                        }
                    }
                }
                endMoving:;
                Position . Passed ( this );
            }
        }

        public BuyAreaResult BuyArea ( Maps . Area toBuy )
        {
            BuyAreaResult temp = new BuyAreaResult
            {
                Area = null,
                Money = 0,
            };

            bool BlockByAreaBuff=false;

            foreach ( var item in toBuy . Buffs )
            {
                BlockByAreaBuff |= item . BlockBuy;
            }

            if ( !BlockByAreaBuff )
            {
                bool BlockByPlayerBuff=false;

                foreach ( var item in Buffs )
                {
                    BlockByPlayerBuff |= item . BlockBuyArea;
                }

                if ( !BlockByPlayerBuff )
                {
                    if ( toBuy . Owner == null )
                    {
                        if ( Money >= toBuy . Price )
                        {
                            Money -= toBuy . Price;
                            temp . Area = toBuy;
                            toBuy . Owner = this;
                            temp . StatusCode = BuyAreaStatusCode . Success;
                            temp . Money += toBuy . Price;
                        }
                        else
                        {
                            temp . StatusCode = BuyAreaStatusCode . MoneyNotEnough;
                        }
                    }
                    else
                    {
                        temp . StatusCode = BuyAreaStatusCode . NotBuyable;
                    }
                }
                else
                {
                    temp . StatusCode = BuyAreaStatusCode . PlayersDebuff;
                }
            }
            else
            {
                temp . StatusCode = BuyAreaStatusCode . AreasDebuff;
            }
            return temp;
        }

        public BuyStockResult BuyStock ( Stocks . Stock toBuy , long number )
        {

            BuyStockResult temp = new BuyStockResult
            {
                Money = 0,
                NumberOfStock=0
            };

            bool canBuy=true;

            foreach ( var item in Buffs )
            {
                canBuy &= item . BlockBuyStock;
            }

            if ( canBuy )
            {
                for ( int haveBuy = 0 ; haveBuy < number ; haveBuy++ )
                {
                    if ( Money >= toBuy . Price )
                    {
                        Money -= toBuy . Price;
                        temp . Money += toBuy . Price;
                        temp . NumberOfStock++;
                    }
                    else
                    {
                        temp . StatusCode = BuyStockStatusCode . MoneyNotEnough;

                        break;
                    }
                    temp . StatusCode = BuyStockStatusCode . Success;
                }
            }
            else
            {
                temp . StatusCode = BuyStockStatusCode . Debuff;
            }

            Stocks [ toBuy ] += temp . NumberOfStock;

            return temp;
        }

        public void ChangeState ( PlayerState state , TimeSpan upTime )
        {
            State = state;
            StateStartDate = Game . Current . Date;
            StateUpTime = upTime;
        }

        public bool ShouldPayForCross
        {
            get
            {
                bool freeOfPay=false;
                foreach ( var item in Buffs )
                {
                    freeOfPay |= item . FreeOfCharge;
                }
                return !freeOfPay;
            }
        }

        public void PayForCross ( Maps . Area area , long money )
        {

        }

        public void GetFromArea ( Maps . Area area , long money )
        {

        }

        public override void NextDay ( )
        {


        }

        public override void UpdateView ( )
        {
            throw new NotImplementedException ( );
        }

        public Player ( XElement saving ) : base ( saving )
        {
           
        }

        public override XElement Save ( )
        {
            var temp= base . Save ( );
          
            return temp;
        }
    }

}